﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.IO;

namespace CommonData
{
    interface TcpRecv
    {
        void onRecv(byte[] bsd);
    }
    enum SocketState
    {
        Connecting,
        Connected,
        Idel
    }
    public class TcpConfig {
        public static int headSize = 4;
        public static int recvBuffSize = 1024 * 64;
        public static int maxPackSize = 64 * 1024;
    }
    class RecvClass : TcpRecv
    {
        private const int headSize = 2;
        public void onRecv(byte[] buffer)
        {
            if (buffer == null)
                return;
            int bufLength = buffer.Length;
            byte[] head = new byte[headSize];
            Buffer.BlockCopy(buffer, 0, head, 0, headSize);
            Array.Reverse(head);
            int headLength = BitConverter.ToInt16(head, 0);
            byte[] headBuffer = new byte[headLength];
            int bodyLength = bufLength - headSize - headLength;
            byte[] bodyBuffer = new byte[bodyLength];
            Buffer.BlockCopy(buffer, headSize, headBuffer, 0, headLength);
            Buffer.BlockCopy(buffer, headSize + headLength, bodyBuffer, 0, bodyLength);
            LuaHelper.getLuaModule().callScript("onRecv", headBuffer, bodyBuffer);
        }
    }
    class BaseNetTcp
    {
        private Socket cTcp = null;
        private SocketState sState = SocketState.Idel;

        private int headSize = TcpConfig.headSize;
        private byte[] recvBuff = new byte[TcpConfig.recvBuffSize];         
        private byte[] surplusBuffer = null;
        private TcpRecv recvEvent = null;

        public void initTcp(string ip, int port, TcpRecv tr)
        {
            Console.WriteLine("basenettcp initTcp");
            cTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            cTcp.BeginConnect(ip, port, new AsyncCallback(onConnect), cTcp);
            Array.Clear(recvBuff, 0, recvBuff.Length);
            sState = SocketState.Connecting;
            recvEvent = tr;
        }
        public void cloes() {
            cTcp.Close();
        }
        public void send(byte[] data)
        {
            byte[] sendBuff = new byte[data.Length + 4];
            byte[] lenBuff = BitConverter.GetBytes(data.Length);
            Array.Reverse(lenBuff);
            Array.Copy(lenBuff, sendBuff, 4);
            Array.Copy(data, 0, sendBuff, 4, data.Length);
            cTcp.BeginSend(sendBuff, 0, sendBuff.Length, SocketFlags.None, new AsyncCallback(onSend), sendBuff.Length);
        }
        private void onConnect(IAsyncResult ar)
        {
            Socket ts = (Socket)ar.AsyncState;
            sState = SocketState.Connected;
            ts.BeginReceive(recvBuff, 0, recvBuff.Length, SocketFlags.None, new AsyncCallback(OnReceive), ts);
            LuaHelper.getLuaModule().callScript("onConnect");
        }
        private void onSend(IAsyncResult ar)
        {
            int len = (int)ar.AsyncState;
            Console.WriteLine("basenettcp onSend sunncess len:" + len);
        }
        private void OnReceive(IAsyncResult ar)
        {
            Socket ts = (Socket)ar.AsyncState;
            int bytesRead = ts.EndReceive(ar);
            if (bytesRead > 0)
            {
                if (surplusBuffer == null)
                {
                    surplusBuffer = new byte[bytesRead];
                    Buffer.BlockCopy(recvBuff, 0, surplusBuffer, 0, bytesRead);
                }
                else
                {
                    byte[] tempByte = new byte[bytesRead];
                    Buffer.BlockCopy(recvBuff, 0, tempByte, 0, bytesRead);
                    surplusBuffer = surplusBuffer.Concat(tempByte).ToArray();
                }
                int haveRead = 0;
                int totalLen = surplusBuffer.Length;
                while (haveRead <= totalLen)
                {
                    if (totalLen - haveRead < headSize)
                    {
                        byte[] byteSub = new byte[totalLen - haveRead];
                        Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead);
                        surplusBuffer = byteSub;
                        break;
                    }
                    byte[] headByte = new byte[headSize];
                    Buffer.BlockCopy(surplusBuffer, haveRead, headByte, 0, headSize);
                    Array.Reverse(headByte);
                    int bodySize = BitConverter.ToInt32(headByte, 0);
                    if (haveRead + headSize + bodySize > totalLen)
                    {
                        byte[] byteSub = new byte[totalLen - haveRead];
                        Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead);
                        surplusBuffer = byteSub;
                        break;
                    }
                    else
                    {
                        byte[] buffer = null;
                        if (bodySize > 0)
                        {
                            buffer = new byte[bodySize];
                            Buffer.BlockCopy(surplusBuffer, haveRead + headSize, buffer, 0, bodySize);
                        }
                        haveRead = haveRead + headSize + bodySize;
                        if (haveRead >= totalLen)
                        {
                            surplusBuffer = null;
                            recvEvent.onRecv(buffer);
                            break;
                        }   
                        recvEvent.onRecv(buffer);
                    }
                }   
            }
            Array.Clear(recvBuff, 0, recvBuff.Length);
            ts.BeginReceive(recvBuff, 0, recvBuff.Length, SocketFlags.None, new AsyncCallback(OnReceive), ts);
        }
    }
}
